package com.nj.api.web.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.nj.api.Constant.Constants;
import com.nj.api.auth.AuthResp;
import com.nj.api.entity.Recharge;
import com.nj.api.entity.User;
import com.nj.api.exception.MsgTipException;
import com.nj.api.service.RechargeService;
import com.nj.api.service.UserService;
import com.nj.api.utils.HttpUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 服务器为客户端创建一个session对象，通过cookie把session唯一的标识保存在客户端，再次请求时，浏览器会将cookie信息传给服务器，服务器根据cookie找到对于的session对象
 */
@RestController
@CrossOrigin
@RequestMapping("User")
public class UserController {
    @Resource
    private UserService userService;
    @Resource
    private ObjectMapper objectMapper;
    @Resource
    private RedisTemplate redisTemplate;//数据验证可以在控制层做
    @Resource
    private RechargeService rechargeService;
    @Value("${timeout}")
    private int timeout;

    @GetMapping("/checkExist/{phone}")//通过唯一的phone判断该用户是否存在
    public Boolean checkExists(@PathVariable String phone){
        return userService.checkExists(phone);
    }

    @PostMapping("/register")
    public Map register(String phone,String password,String code){
        return userService.register(phone,password,code);
    }
    @PostMapping("/login")//密码登录
    public Map login(String phone,String password){
        User user = userService.login(phone, password);
        Boolean auth = !StringUtils.isBlank(user.getName());
        //模仿session 给登录的用户一个唯一的标识
        String token = UUID.randomUUID().toString().replace("-", "").toUpperCase();
        //把token存在redis

        System.out.println(token);
        redisTemplate.opsForValue().set(token,user,timeout, TimeUnit.MINUTES);


        return new HashMap(){{
            put("success",true);
            put("auth",auth);//是否实名认证 false为未实名认证
            put("token",token);
        }};
    }
    @PostMapping("/login2")//短信登录
    public Map login2(String phone,String code){
        String realCode = (String) redisTemplate.opsForValue().get("code:login:" + phone);
        if (StringUtils.isBlank(realCode)||!realCode.equals(code)){
            throw new MsgTipException("验证码不正确");
        }
        User user =userService.getUserByPhone(phone);
        Boolean auth =!StringUtils.isBlank(user.getName());
        return new HashMap(){{
            put("success",true);
            put("auth",auth);//是否实名认证 false为未实名认证
        }};
    }
    @PostMapping("/auth")//实名认证
    public Map auth(String name,String idCard,@RequestHeader String token) throws Exception {
        String host = "https://sxidcheck.market.alicloudapi.com";
        String path = "/idcard/check";
        String method = "POST";
        String appcode = "68ffd8aa9ec34a20901688729a3ec389";
        Map<String, String> headers = new HashMap<String, String>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appcode);
        Map<String, String> querys = new HashMap<String, String>();
        querys.put("name", name);
        querys.put("idCard", idCard);
        Map<String, String> bodys = new HashMap<String, String>();

        HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);

        //获取response的body
        String result = EntityUtils.toString(response.getEntity());
        System.out.println(result);
        AuthResp authResp = objectMapper.readValue(result, AuthResp.class);
        if (authResp.getCode()==0){//实名成功
            //把实名信息保存在数据库
            User user = (User) redisTemplate.opsForValue().get(token);

            user.setName(name);
            user.setIdCard(idCard);
            userService.updateById(user);

            return new HashMap(){{
                put("success",true);
            }};
        }else {
            throw new MsgTipException("姓名和身份证不匹配");
        }
    }

    @GetMapping("/isLogin")//是否登录，登录返回ture
    public boolean isLogin(@RequestHeader String token){
        System.out.println("--------------isLogin---------------------------");
       User user = (User) redisTemplate.opsForValue().get(token);
       return user != null;
    }
    @GetMapping("/info")
    public User info(@RequestHeader String token){
        System.out.println("--------------info------------------------");
        User user = (User) redisTemplate.opsForValue().get(token);
        String format = Constants.SDF19.format(user.getLastLoginTime());
        System.out.println(format);
        DateTimeFormatter sdf19 = Constants.SDF19;
        LocalDateTime parse = LocalDateTime.parse(format, sdf19);
        System.out.println(parse);
        user.setLastLoginTime(parse);
        //将redis里面的日期格式化成字符串，在格式成日期
        System.out.println(user);
        System.out.println("--------------------------------");
        return user;
    }

    @GetMapping("/headerImage/**")//？这个方法是什么时候调用的(肯定不是异步请求调用的),headerImage/**是从哪里读取的,输出流是输向何方
    //此方法的作用是让页面显示图片,？页面如何通过这个方法显示图片
    public void showImage(HttpServletRequest request, HttpServletResponse response) throws IOException {
        System.out.println("--------------------showImage--------------------------");
//        String fullPath = "F:/headerImage/"+filename;
        //uri:/user/headerImage/12/47/75/65/16/2
//        http://127.0.0.1/User/headerImage/30/38/21/54/18/2?0.3666775459486068
        String uri = request.getRequestURI();// ？这个地址从哪来的
        String filename = uri.substring(18);
        String fullPath = "F:/headerImage/"+filename;

        FileInputStream fis = new FileInputStream(fullPath);
        ServletOutputStream ops = response.getOutputStream();
        byte[] bytes = new byte[1024];
        int len ;
        while ((len=fis.read(bytes))!=-1){
            ops.write(bytes,0,len);
        }

        fis.close();
        ops.close();
    }
    @PostMapping("/upload")//?vue是如何通过字符串来改变图片的
    public String upload(MultipartFile file,@RequestHeader String token) throws IOException {
//        String filename = file.getOriginalFilename();如果用户上传一个图片就存一个图片会导致磁盘资源浪费
        User user = (User) redisTemplate.opsForValue().get(token);
        String filename = user.getId().toString();//所以用id来标识图片的名字，这样同一个id上传一个图片会覆盖之前上传的图片
        //为防止用一个目录下存放过多文件导致系统问题，可以将这些分别存储在不同的目录下（目录分离技术）
        //“/0~99/0~99/0~99/0~99/0~99”
        String paths="";
        if (StringUtils.isBlank(user.getHeaderImage())){
            for (int i = 0; i < 5; i++) {
                paths+="/"+new Random().nextInt(100);
            }
        }else {
            String headerImage = user.getHeaderImage();
            //http://127.0.0.1/User/headerImage/30/38/21/54/18/2
            int index=headerImage.indexOf("/User/headerImage");
            int start = index+17;
            int end = headerImage.lastIndexOf("/");
            paths=headerImage.substring(start,end);
        }
        //"F:/headerImage/0~99/0~99/0~99/0~99/0~99/filename
        File savePathFile = new File("F:/headerImage"+paths);
        savePathFile.mkdirs();
        File f = new File( savePathFile, filename);
        file.transferTo(f);//上传地址和下载地址不能一样
        //同步数据库
        String headerImage = "http://127.0.0.1/User/headerImage"+paths+"/"+filename;//?为什么保存在数据库的地址是这样的
        user.setHeaderImage(headerImage);
        redisTemplate.opsForValue().set(token,user,timeout,TimeUnit.MINUTES);
        userService.updateById(user);
        //? 在路径的后面凭借随机的参数，解决缓存导致的图片没有更新
        return headerImage+"?"+Math.random();
    }
    @GetMapping("/getRecharge")
    public List<Recharge> getRecharge(){
        return rechargeService.list();
    }
}
